////////////////////////////////////
// RegionCreator				  //
// by Rutger Storm                //
//                                //
// File: RegionCreatorWindow.cpp  // 
// Desc: Declaration of the       //
//			PortScannerWindow     //
//			class.				  //
////////////////////////////////////

#include "RegionCreatorWindow.h"
#include <stdio.h>

///////////////////////////////////////////////
// RegionCreatorWindow::RegionCreatorWindow
///////////////////////////////////////////////

RegionCreatorWindow::RegionCreatorWindow(char *ClassName, char *WindowTitle, DWORD dwStyles, RECT *rect, HINSTANCE hInstance){
	m_pClassName	= ClassName;
	m_pWindowTitle	= WindowTitle;
	m_pRect			= rect;
	m_hInstance		= hInstance;
	m_dwStyles		= dwStyles;

	RECT desktopRect;
	GetWindowRect(GetDesktopWindow(),&desktopRect);

	int wWidth	=	m_pRect->right	-	m_pRect->left;
	int wHeight	=	m_pRect->bottom	-	m_pRect->top;

	m_pRect->left	=	((desktopRect.right		-	desktopRect.left)	-	wWidth)		/2;
	m_pRect->right	=	((desktopRect.right		-	desktopRect.left)	+	wWidth)		/2;
	m_pRect->top	=	((desktopRect.bottom	-	desktopRect.top)	-	wHeight)	/2;
	m_pRect->bottom	=	((desktopRect.bottom	-	desktopRect.top)	+	wHeight)	/2;
}

///////////////////////////////////////////////
// RegionCreatorWindow::~RegionCreatorWindow
///////////////////////////////////////////////

RegionCreatorWindow::~RegionCreatorWindow() {

	// Destroy the render window
	if ( m_hWnd ) DestroyWindow( m_hWnd );
	m_hWnd = NULL;
}

///////////////////////////////////////////////
// RegionCreatorWindow::BuildGui()
///////////////////////////////////////////////

void RegionCreatorWindow::BuildGUI() {
	
	// Create and show our buttons
	m_hOpenButton = CreateWindow("BUTTON", "Open", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 10, 10, 80, 30, m_hWnd,
		(HMENU)IDB_OPEN, m_hInstance, NULL);
	m_hGoButton = CreateWindow("BUTTON", "Go", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 400, 10, 80, 30, m_hWnd,
		(HMENU)IDB_GO, m_hInstance, NULL);

	// Create and show our edit boxes
	m_hRedColorEdit = CreateWindow("EDIT", "0", WS_CHILD | WS_VISIBLE | ES_NUMBER | WS_BORDER, 10, 60, 100, 20, m_hWnd,
		(HMENU)IDE_RED, m_hInstance, NULL);
	m_hGreenColorEdit = CreateWindow("EDIT", "0", WS_CHILD | WS_VISIBLE | ES_NUMBER | WS_BORDER, 120, 60, 100, 20, m_hWnd,
		(HMENU)IDE_GREEN, m_hInstance, NULL);
	m_hBlueColorEdit = CreateWindow("EDIT", "0", WS_CHILD | WS_VISIBLE | ES_NUMBER | WS_BORDER, 230, 60, 100, 20, m_hWnd,
		(HMENU)IDE_BLUE, m_hInstance, NULL);
	m_hPathEdit - CreateWindow("EDIT", "Fill in path here.", WS_CHILD | WS_VISIBLE | ES_NUMBER | WS_BORDER, 100, 10, 280, 20, m_hWnd,
		(HMENU)IDE_PATH, m_hInstance, NULL);

	// Create and show our labels
	m_hRedColorLabel = CreateWindow("STATIC", "Red Color", WS_CHILD | WS_VISIBLE, 10, 90, 100, 20, m_hWnd,
		(HMENU)IDS_RED, m_hInstance, NULL);
	m_hGreenColorLabel = CreateWindow("STATIC", "Green Color", WS_CHILD | WS_VISIBLE, 120, 90, 100, 20, m_hWnd,
		(HMENU)IDS_GREEN, m_hInstance, NULL);
	m_hBlueColorLabel = CreateWindow("STATIC", "Blue Color", WS_CHILD | WS_VISIBLE, 230, 90, 100, 20, m_hWnd,
		(HMENU)IDS_BLUE, m_hInstance, NULL);

	// Create and show our output area
	m_hDisplayArea = CreateWindow("STATIC", "RegionCreator v1", WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 120, 470, 380, m_hWnd,
		(HMENU)IDT_OUTPUT, m_hInstance, NULL);
}

///////////////////////////////////////////////
// RegionCreatorWindow::WinProc
///////////////////////////////////////////////

LRESULT CALLBACK RegionCreatorWindow::WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	// Define our true window processor here

	switch(uMsg)
	{
		// If the user wants to close the application
	case WM_DESTROY:
		// then close it
		PostQuitMessage(WM_QUIT);
		break;
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDB_GO:
			if(validateInput()) //makeRegion();
			break;
		case IDB_OPEN:
			DoFileOpen();
			break;
		}
	default:
		// Process the left-over messages
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}

	// If something was not done, let it go
	return 0;
}

///////////////////////////////////////////////
// RegionCreatorWindow::validateInput()
///////////////////////////////////////////////
BOOL RegionCreatorWindow::validateInput() {
	// Validate open file HERE

	// Validate input
	BOOL bSuccess;
	GetDlgItemInt(m_hWnd, IDE_RED, &bSuccess, FALSE);
	if(bSuccess != FALSE){
		GetDlgItemInt(m_hWnd, IDE_GREEN, &bSuccess, FALSE);
		if(bSuccess != FALSE){
			GetDlgItemInt(m_hWnd, IDE_BLUE, &bSuccess, FALSE);
			if(bSuccess != FALSE){
				return TRUE;
			}
		}
	}
	MessageBox(m_hWnd, "Invalid Entry,\nPlease re-enter information", "Invalid Data Entered", 
		MB_OK | MB_ICONEXCLAMATION);
	return FALSE;
}

///////////////////////////////////////////////
// RegionCreatorWindow::makeRegion()
///////////////////////////////////////////////
BOOL RegionCreatorWindow::makeRegion() {
	/*
	// handle for the supplied bitmap
	HBITMAP hBmp;

	// transparent color components
	BYTE jRed,jGreen,jBlue;

	// processed region
	HRGN hRegion;

	// supplied filename
	char szFile[MAX_PATH];
	*/
	return true;
}

BOOL RegionCreatorWindow::DoFileOpen()
{
	OPENFILENAME ofn;
	char szFileName[MAX_PATH] = "";

	ZeroMemory(&ofn, sizeof(ofn));

	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = m_hWnd;
	ofn.lpstrFilter = "Bitmap Files (*.bmp)\0*.bmp\0";
	ofn.lpstrFile = szFileName;
	ofn.nMaxFile = MAX_PATH;
	ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
	ofn.lpstrDefExt = "txt";

	if(GetOpenFileName(&ofn))
	{
		return true;
	}
}

///////////////////////////////////////////////
// RegionCreatorWindow::ScanRegion()
///////////////////////////////////////////////
// -------------------------------------------------------------------------------------
// Scan a bitmap and return a perfect fit region.
// The caller must release the memory...
// (this method starts with a full region and excludes inside the loop)
// -------------------------------------------------------------------------------------
HRGN RegionCreatorWindow::ScanRegion(HBITMAP pBitmap, BYTE jTranspR, BYTE jTranspG, BYTE jTranspB)
{
	// bitmap width and height
	WORD wBmpWidth,wBmpHeight;

	// the final region and a temporary region
	HRGN hRgn, hTmpRgn;

	// 24bit pixels from the bitmap
	BYTE *pPixels = Get24BitPixels(pBitmap, &wBmpWidth, &wBmpHeight);
	if (!pPixels) return NULL;

	// create our working region
	hRgn = CreateRectRgn(0,0,wBmpWidth,wBmpHeight);
	if (!hRgn) { delete pPixels; return NULL; }

	// ---------------------------------------------------------
	// scan the bitmap
	// ---------------------------------------------------------
	DWORD p=0;
	for (WORD y=0; y<wBmpHeight; y++)
	{
		for (WORD x=0; x<wBmpWidth; x++)
		{
			BYTE jRed   = pPixels[p+2];
			BYTE jGreen = pPixels[p+1];
			BYTE jBlue  = pPixels[p+0];

			if (jRed == jTranspR && jGreen == jTranspG && jBlue == jTranspB)
			{
				// remove transparent color from region
				hTmpRgn = CreateRectRgn(x,y,x+1,y+1);
				CombineRgn(hRgn, hRgn, hTmpRgn, RGN_XOR);
				DeleteObject(hTmpRgn);
			}

			// next pixel
			p+=3;
		}
	}

	// release pixels
	delete pPixels;

	// return the region
	return hRgn;
}


///////////////////////////////////////////////
// RegionCreatorWindow::Get24BitPixels()
///////////////////////////////////////////////
// -------------------------------------------------------------------------------------
// Return bitmap pixels in 24bits format.
// The caller must release the memory...
// -------------------------------------------------------------------------------------
BYTE* RegionCreatorWindow::Get24BitPixels(HBITMAP pBitmap, WORD *pwWidth, WORD *pwHeight)
{
	// a bitmap object just to get bitmap width and height
	BITMAP bmpBmp;

	// pointer to original bitmap info
	LPBITMAPINFO pbmiInfo;

	// bitmap info will hold the new 24bit bitmap info
	BITMAPINFO bmiInfo;

	// width and height of the bitmap
	WORD wBmpWidth, wBmpHeight;

	// ---------------------------------------------------------
	// get some info from the bitmap
	// ---------------------------------------------------------
	GetObject(pBitmap, sizeof(bmpBmp),&bmpBmp);
	pbmiInfo   = (LPBITMAPINFO)&bmpBmp;

	// get width and height
	wBmpWidth  = (WORD)pbmiInfo->bmiHeader.biWidth;
	wBmpWidth -= (wBmpWidth%4);                       // width is 4 byte boundary aligned.
	wBmpHeight = (WORD)pbmiInfo->bmiHeader.biHeight;

	// copy to caller width and height parms
	*pwWidth  = wBmpWidth;
	*pwHeight = wBmpHeight;
	// ---------------------------------------------------------

	// allocate width * height * 24bits pixels
	BYTE *pPixels = new BYTE[wBmpWidth*wBmpHeight*3];
	if (!pPixels) return NULL;

	// get user desktop device context to get pixels from
	HDC hDC = GetWindowDC(NULL);

	// fill desired structure
	bmiInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmiInfo.bmiHeader.biWidth = wBmpWidth;
	bmiInfo.bmiHeader.biHeight = -wBmpHeight;
	bmiInfo.bmiHeader.biPlanes = 1;
	bmiInfo.bmiHeader.biBitCount = 24;
	bmiInfo.bmiHeader.biCompression = BI_RGB;
	bmiInfo.bmiHeader.biSizeImage = wBmpWidth*wBmpHeight*3;
	bmiInfo.bmiHeader.biXPelsPerMeter = 0;
	bmiInfo.bmiHeader.biYPelsPerMeter = 0;
	bmiInfo.bmiHeader.biClrUsed = 0;
	bmiInfo.bmiHeader.biClrImportant = 0;

	// get pixels from the original bitmap converted to 24bits
	int iRes = GetDIBits(hDC,pBitmap,0,wBmpHeight,(LPVOID)pPixels,&bmiInfo,DIB_RGB_COLORS);

	// release the device context
	ReleaseDC(NULL,hDC);

	// if failed, cancel the operation.
	if (!iRes)
	{
		delete pPixels;
		return NULL;
	};

	// return the pixel array
	return pPixels;
}


///////////////////////////////////////////////
// RegionCreatorWindow::SaveRegion()
///////////////////////////////////////////////
// -------------------------------------------------------------------------------------
// Save a region to disk
// -------------------------------------------------------------------------------------
BOOL RegionCreatorWindow::SaveRegion(HRGN hRgn, char *szFile)
{
	// get the size of the region object
	int iSize = GetRegionData(hRgn, 0,0);

	// allocate space for it
	LPRGNDATA pData = new RGNDATA[iSize];
	if (!pData) return false;

	// get the region as binary data
	GetRegionData(hRgn, iSize, pData);

	// save
	FILE *f = fopen(szFile, "wb");
	if (!f) { delete pData; return false; }
	fwrite(pData, 1, iSize, f);
	fclose(f);

	delete pData;

	return true;
}